﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Interop.Excel;

namespace PCR.Logic
{
    using PCR.Base;
    
    /// <summary>
    /// Control the input and output with external application
    /// </summary>
    internal class IOManager : IIOManager
    {
        /// <summary>
        /// Import the patient reports from specified excel file,
        /// the input excel file format must confirm to our rules
        /// </summary>
        /// <typeparam name="T">This template type could be IVirusType, 
        ///     IPatientReport, or IStdCurve</typeparam>
        /// <param name="excelFile">Output excel file name</param>
        /// <returns>The list of the specified data</returns>
        public IList<T> ImportFromExcel<T>(string excelFile)
        {
            if (typeof(T) == typeof(IPatientReport))
            {
                return (IList<T>)ImportPatientReports(excelFile);
            }
            else if (typeof(T) == typeof(IStdCurve))
            {
                return (IList<T>)ImportStdCurves(excelFile);
            }
            else if (typeof(T) == typeof(IVirusType))
            {
                return (IList<T>)ImportVirusTypes(excelFile);
            }
            else
            {
                System.Diagnostics.Debug.Assert(false,
                    "Only support : IPatientReport, IStdCurve, IVirusType");

                return null;
            }
        }

        /// <summary>
        /// Export the patient reports to specified excel file,
        /// </summary>
        /// <typeparam name="T">This template type could be IVirusType, 
        ///     IPatientReport, or IStdCurve</typeparam>
        /// <param name="excelFile">Output excel file name</param>
        /// <returns>The list of the specified data</returns>
        public bool ExportToExcel<T>(string excelFile, IList<T> dataList)
        {
            if (typeof(T) == typeof(IPatientReport))
            {
                return ExportPatientReport(excelFile, (IList<IPatientReport>)dataList);
            }
            else if (typeof(T) == typeof(IStdCurve))
            {
                return ExportStdCurves(excelFile, (IList<IStdCurve>)dataList);
            }
            else if (typeof(T) == typeof(IVirusType))
            {
                return ExportVirusTypes(excelFile, (IList<IVirusType>)dataList);
            }
            else
            {
                System.Diagnostics.Debug.Assert(false,
                    "Only support : IPatientReport, IStdCurve, IVirusType");
                
                return false;
            }
        }

        protected IList<IPatientReport> ImportPatientReports(string excelFile)
        {
            // Should existed
            System.Diagnostics.Debug.Assert(System.IO.File.Exists(excelFile));
            IList<IPatientReport> patientReports = new List<IPatientReport>();

            {
                ApplicationClass excelApp = null;
                Workbook workbooks = null;

                uint iCurrentRow = 2;
                string sheetName = "";
                try
                {
                    excelApp = new ApplicationClass();
                    excelApp.Visible = false;

                    workbooks = excelApp.Workbooks.Open(excelFile);
                    foreach (Worksheet sheet in workbooks.Worksheets)
                    {
                        iCurrentRow = 2;
                        sheetName = sheet.Name;
                        if (!sheet.Name.StartsWith(PCRRoot.GetPatientHeader(), StringComparison.OrdinalIgnoreCase))
                        {
                            continue;
                        }

                        for (; iCurrentRow <= sheet.UsedRange.Rows.Count; iCurrentRow++)
                        {
                            IPatientReport report = PCRRoot.Instance.CreateObject(ObjectType.PatientReport) as IPatientReport;
                            report.ReportDate = DateTime.Parse(((Range)(sheet.UsedRange[iCurrentRow, 1])).Value2 as string);
                            report.ReportID = ((Range)(sheet.UsedRange[iCurrentRow, 2])).Value2 as string;
                            report.Name = ((Range)(sheet.UsedRange[iCurrentRow, 3])).Value2 as string;
                            report.Age = uint.Parse(((Range)(sheet.UsedRange[iCurrentRow, 4])).Value2 as string);
                            report.Gender = PCRRoot.GenderValue(((Range)(sheet.UsedRange[iCurrentRow, 5])).Value2 as string);
                            report.CheckDate = DateTime.Parse(((Range)(sheet.UsedRange[iCurrentRow, 6])).Value2 as string);
                            report.SampleID = ((Range)(sheet.UsedRange[iCurrentRow, 7])).Value2 as string;
                            report.SampleReceiveDate = DateTime.Parse(((Range)(sheet.UsedRange[iCurrentRow, 8])).Value2 as string);
                            report.CheckMethod = PCRRoot.CheckMethodValue(((Range)(sheet.UsedRange[iCurrentRow, 9])).Value2 as string);
                            report.SampleType = PCRRoot.SampleTypeValue(((Range)(sheet.UsedRange[iCurrentRow, 10])).Value2 as string);
                            report.SampleState = PCRRoot.SampleStateValue(((Range)(sheet.UsedRange[iCurrentRow, 11])).Value2 as string);
                            report.CellPrinciple = ((Range)(sheet.UsedRange[iCurrentRow, 16])).Value2 as string;
                            report.PathologyPrinciple = ((Range)(sheet.UsedRange[iCurrentRow, 17])).Value2 as string;
                            if (report.CellPrinciple == null) report.CellPrinciple = PCRRoot.GetNothingString();
                            if (report.PathologyPrinciple == null) report.PathologyPrinciple = PCRRoot.GetNothingString();

#region CHECK_VIRUS_TYPES

                            string str12 = ((Range)(sheet.UsedRange[iCurrentRow, 12])).Value2 as string;
                            string str13 = ((Range)(sheet.UsedRange[iCurrentRow, 13])).Value2 as string;
                            string str14 = ((Range)(sheet.UsedRange[iCurrentRow, 14])).Value2 as string;
                            //if (!str12.StartsWith(PCRRoot.GetTypeHeader(), StringComparison.OrdinalIgnoreCase))
                            //{
                            //    throw new Exception();
                            //}

                            //str12 = str12.Substring(PCRRoot.GetTypeHeader().Length);
                            if (string.IsNullOrEmpty(str12) || str12.Length <= 0)
                            {
                                throw new Exception();
                            }

                            string[] strTypes = str12.Split(PCRRoot.GetSpitterSign().ToArray<char>());
                            string[] strVirusCTs = str13.Split(PCRRoot.GetSpitterSign().ToArray<char>());
                            string[] strGeneCTs = str14.Split(PCRRoot.GetSpitterSign().ToArray<char>());
                            if (strTypes.Length != strVirusCTs.Length || strVirusCTs.Length != strGeneCTs.Length || strGeneCTs.Length != strTypes.Length)
                            {
                                throw new Exception();
                            }

                            foreach (string strType in strTypes)
                            {
                                IVirusType virusType = PCRRoot.VirusTypeValue(strType);
                                if (virusType == null)
                                {
                                    throw new Exception();
                                }
                            }

#endregion
                            for (int p = 0; p < strTypes.Length;p++ )
                            {
                                IPatientVirus virus = PCRRoot.Instance.CreateObject(ObjectType.PatientVirus) as IPatientVirus;
                                virus.VirusTypeID = PCRRoot.VirusTypeValue(strTypes[p]).ObjectID;
                                virus.VirusCTVal = double.Parse(strVirusCTs[p]);
                                virus.ReferCellCTVal = double.Parse(strGeneCTs[p]);

                                report.PatientVirusList.Add(virus);
                            }

                            patientReports.Add(report);
                        }
                    }                    
                }
                catch
                {
                    ThrowExcelError(excelFile, sheetName, iCurrentRow);
                    patientReports.Clear();
                    patientReports = null;
                }
                finally
                {
                    if (workbooks != null)
                        workbooks.Close();
                    excelApp.Quit();
                }
            }
            
            return patientReports;
        }

        protected bool ExportPatientReport(string excelFile, IList<IPatientReport> dataList)
        {            
            // Should not existed
            //System.Diagnostics.Debug.Assert(!System.IO.File.Exists(excelFile));
            
            bool bRst = true;    
            {
                ApplicationClass excelApp = null;
                Workbook workbooks = null;


                try
                {
                    excelApp = new ApplicationClass();
                    excelApp.Visible = false;

                    workbooks = excelApp.Workbooks.Add(XlWBATemplate.xlWBATWorksheet);

                    Worksheet worksheet = (Worksheet)(workbooks.Worksheets[1]);
                    worksheet.Name = PCRRoot.GetPatientHeader();

                    //写入第一行标题字段 
                    //报告日期	报告编号	病人姓名	年龄	性别	检测日期	样本编号	标本接收日期	检测方法	标本类型	标本状态	高危型	检测CT值	参考基因CT值	细胞学	病理学
                    string[] patientHeader = { "报告日期","报告编号","病人姓名","年龄","性别","检测日期",
                                                 "样本编号","标本接收日期","检测方法","标本类型","标本状态",
                                                 "亚型类型","检测CT值","参考基因CT值","感染单位","细胞学","病理学" };
                    for (int iCol = 1; iCol <= patientHeader.Length; iCol++)
                    {
                        worksheet.Cells[1, iCol] = patientHeader[iCol-1];
                    }

                    //写入数据
                    for (int iReport = 0; iReport < dataList.Count;iReport++ )
                    {
                        IPatientReport report = dataList[iReport];
                        worksheet.Cells[iReport + 2, 1] = report.ReportDate.ToShortDateString();
                        worksheet.Cells[iReport + 2, 2] = report.ReportID;
                        worksheet.Cells[iReport + 2, 3] = report.Name;
                        worksheet.Cells[iReport + 2, 4] = report.Age.ToString();
                        worksheet.Cells[iReport + 2, 5] = PCRRoot.GenderString(report.Gender);
                        worksheet.Cells[iReport + 2, 6] = report.CheckDate.ToShortDateString();
                        worksheet.Cells[iReport + 2, 7] = report.SampleID;
                        worksheet.Cells[iReport + 2, 8] = report.SampleReceiveDate.ToShortDateString();
                        worksheet.Cells[iReport + 2, 9] = PCRRoot.CheckMethodString(report.CheckMethod);
                        worksheet.Cells[iReport + 2, 10] = PCRRoot.SampleTypeString(report.SampleType);
                        worksheet.Cells[iReport + 2, 11] = PCRRoot.SampleStateString(report.SampleState);

                        if (report.PatientVirusList.Count > 0)
                        {
                            string str12 = "";
                            string str13 = "";
                            string str14 = "";
                            string str15 = "";
                            for (int iVirusCnt = 0; iVirusCnt < report.PatientVirusList.Count; iVirusCnt++ )
                            {
                                //if (iVirusCnt == 0) str12 = PCRRoot.GetTypeHeader();
                                str12 += PCRRoot.VirusTypeString(report.PatientVirusList[iVirusCnt].VirusTypeID);
                                str13 += report.PatientVirusList[iVirusCnt].VirusCTVal.ToString();
                                str14 += report.PatientVirusList[iVirusCnt].ReferCellCTVal.ToString();
                                str15 += report.PatientVirusList[iVirusCnt].Exponent.ToString();
                                if (iVirusCnt < report.PatientVirusList.Count - 1)
                                {
                                    str12 += PCRRoot.GetSpitterSign();
                                    str13 += PCRRoot.GetSpitterSign();
                                    str14 += PCRRoot.GetSpitterSign();
                                    str15 += PCRRoot.GetSpitterSign();
                                }
                            }

                            worksheet.Cells[iReport + 2, 12] = str12;
                            worksheet.Cells[iReport + 2, 13] = str13;
                            worksheet.Cells[iReport + 2, 14] = str14;
                            worksheet.Cells[iReport + 2, 15] = str15;
                        }
                        else
                        {
                            worksheet.Cells[iReport + 2, 12] = PCRRoot.GetNothingString();
                            worksheet.Cells[iReport + 2, 13] = 0;
                            worksheet.Cells[iReport + 2, 14] = 0;
                            worksheet.Cells[iReport + 2, 15] = 0;
                        }

                        worksheet.Cells[iReport + 2, 16] = report.CellPrinciple;
                        worksheet.Cells[iReport + 2, 17] = report.PathologyPrinciple;
                    }

                    //保存文件
                    worksheet.Columns.EntireColumn.AutoFit();
                    workbooks.Saved = true;
                    workbooks.SaveCopyAs(excelFile);
                }
                catch
                {
                    bRst = false;
                }
                finally
                {
                    if (workbooks != null)
                        workbooks.Close();
                    excelApp.Quit();
                }
            }
            return bRst;
        }

        protected IList<IStdCurve> ImportStdCurves(string excelFile)
        {
            // Should existed
            System.Diagnostics.Debug.Assert(System.IO.File.Exists(excelFile));
            IList<IStdCurve> stdCurves = new List<IStdCurve>();

            {
                ApplicationClass excelApp = null;
                Workbook workbooks = null;

                uint iCurrentRow = 2;
                string sheetName = "";
                try
                {
                    excelApp = new ApplicationClass();
                    excelApp.Visible = false;

                    workbooks = excelApp.Workbooks.Open(excelFile);
                    foreach (Worksheet sheet in workbooks.Worksheets)
                    {
                        iCurrentRow = 2;
                        sheetName = sheet.Name;
                        if (!sheet.Name.StartsWith(PCRRoot.GetStdCurveHeader(), StringComparison.OrdinalIgnoreCase))
                        {
                            continue;
                        }

                        IStdCurve std = PCRRoot.Instance.CreateObject(ObjectType.StdCurve) as IStdCurve;

                        for (; iCurrentRow <= sheet.UsedRange.Rows.Count; iCurrentRow++)
                        {
                            if (iCurrentRow == 2)
                            {
                                std.Name = ((Range)(sheet.UsedRange[iCurrentRow, 1])).Value2 as string;
                                std.Description = ((Range)(sheet.UsedRange[iCurrentRow, 2])).Value2 as string;
                            }

                            IStdSampleData data = PCRRoot.Instance.CreateObject(ObjectType.StdSampleData) as IStdSampleData;
                            data.Valid = true;
                            data.CTVal = double.Parse(((Range)(sheet.UsedRange[iCurrentRow, 3])).Value2.ToString());
                            data.CellCount = UInt64.Parse(((Range)(sheet.UsedRange[iCurrentRow, 4])).Value2.ToString());

                            std.SampleDataList.Add(data);
                        }

                        stdCurves.Add(std);
                    }
                }
                catch
                {
                    ThrowExcelError(excelFile, sheetName, iCurrentRow); 
                    stdCurves.Clear();
                    stdCurves = null;
                }
                finally
                {
                    if (workbooks != null)
                        workbooks.Close();
                    excelApp.Quit();
                }
            }

            return stdCurves;
        }

        protected bool ExportStdCurves(string excelFile, IList<IStdCurve> dataList)
        {
            // Should not existed
            System.Diagnostics.Debug.Assert(!System.IO.File.Exists(excelFile));
            
            {
                ApplicationClass excelApp = null;
                Workbook workbooks = null;

                try
                {
                    excelApp = new ApplicationClass();
                    excelApp.Visible = false;

                }
                catch
                {
                }
                finally
                {
                    if (workbooks != null)
                        workbooks.Close();
                    excelApp.Quit();
                }
            }        
            return false;
        }

        protected IList<IVirusType> ImportVirusTypes(string excelFile)
        {
            // Should existed
            System.Diagnostics.Debug.Assert(System.IO.File.Exists(excelFile));
            IList<IVirusType> virusTypes = new List<IVirusType>();

            {
                ApplicationClass excelApp = null;
                Workbook workbooks = null;

                uint iCurrentRow = 2;
                string sheetName = "";
                try
                {
                    excelApp = new ApplicationClass();
                    excelApp.Visible = false;

                    workbooks = excelApp.Workbooks.Open(excelFile);
                    foreach (Worksheet sheet in workbooks.Worksheets)
                    {
                        iCurrentRow = 2;
                        sheetName = sheet.Name;
                        if (!sheet.Name.StartsWith(PCRRoot.GetVirusTypeHeader(), StringComparison.OrdinalIgnoreCase))
                        {
                            continue;
                        }

                        for (; iCurrentRow <= sheet.UsedRange.Rows.Count; iCurrentRow++)
                        {
                            IVirusType type = PCRRoot.Instance.CreateObject(ObjectType.VirusType) as IVirusType;

                            type.Name = ((Range)(sheet.UsedRange[iCurrentRow, 1])).Value2 as string;
                            type.EVal = (double)(((Range)(sheet.UsedRange[iCurrentRow, 2])).Value2);
                            type.KVal = (double)(((Range)(sheet.UsedRange[iCurrentRow, 3])).Value2);
                            type.BVal = (double)(((Range)(sheet.UsedRange[iCurrentRow, 4])).Value2);
                            type.VirusDefineType = PCRRoot.VirusDefineTypeValue(((Range)(sheet.UsedRange[iCurrentRow, 5])).Value2 as string);
                            virusTypes.Add(type);
                        }
                    }
                }
                catch
                {
                    ThrowExcelError(excelFile, sheetName, iCurrentRow); 
                    virusTypes.Clear();
                    virusTypes = null;
                }
                finally
                {
                    if (workbooks != null)
                        workbooks.Close();
                    excelApp.Quit();
                }
            }

            return virusTypes;
        }

        protected bool ExportVirusTypes(string excelFile, IList<IVirusType> dataList)
        {
            // Should not existed
            System.Diagnostics.Debug.Assert(!System.IO.File.Exists(excelFile));

            {
                ApplicationClass excelApp = null;
                Workbook workbooks = null;

                try
                {
                    excelApp = new ApplicationClass();
                    excelApp.Visible = false;

                }
                catch
                {
                }
                finally
                {
                    if (workbooks != null)
                        workbooks.Close();
                    excelApp.Quit();
                }
            }
            return false;
        }

        protected void ThrowExcelError(string strFile, string sheetName, uint row)
        {
            string strError = string.Format("文件名：{0}\n表格名：{1}\n行：{2}\n请参照HPV模块格式！",strFile,sheetName,row);
            System.Windows.Forms.MessageBox.Show(strError, "Excel格式错误!", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
        }
    }
}
